#include "stdafx.h"
#include "Toolkit.h"

#include <stdlib.h>

namespace Framework {

bool Toolkit::CheckLineBox(d3d::BoundingBox box, D3DXVECTOR3 L1, D3DXVECTOR3 L2, D3DXVECTOR3 &Hit) {
    if (L2.x < box._min.x && L1.x < box._min.x) return false;
    if (L2.x > box._max.x && L1.x > box._max.x) return false;
    if (L2.y < box._min.y && L1.y < box._min.y) return false;
    if (L2.y > box._max.y && L1.y > box._max.y) return false;
    if (L2.z < box._min.z && L1.z < box._min.z) return false;
    if (L2.z > box._max.z && L1.z > box._max.z) return false;
    if (L1.x > box._min.x && L1.x < box._max.x &&
            L1.y > box._min.y && L1.y < box._max.y &&
            L1.z > box._min.z && L1.z < box._max.z) {
        Hit = L1;
        return true;
    }
    if ( (GetIntersection(L1.x-box._min.x, L2.x-box._min.x, L1, L2, Hit) && InBox(Hit, box, 1))
            || (GetIntersection(L1.y-box._min.y, L2.y-box._min.y, L1, L2, Hit) && InBox(Hit, box, 2))
            || (GetIntersection(L1.z-box._min.z, L2.z-box._min.z, L1, L2, Hit) && InBox(Hit, box, 3))
            || (GetIntersection(L1.x-box._max.x, L2.x-box._max.x, L1, L2, Hit) && InBox(Hit, box, 1))
            || (GetIntersection(L1.y-box._max.y, L2.y-box._max.y, L1, L2, Hit) && InBox(Hit, box, 2))
            || (GetIntersection(L1.z-box._max.z, L2.z-box._max.z, L1, L2, Hit) && InBox(Hit, box, 3)))
        return true;

    return false;
}

bool Toolkit::CheckLineSphere(d3d::BoundingSphere sphere, D3DXVECTOR3 L1, D3DXVECTOR3 L2) {
    D3DXVECTOR3 kDiff = L1 - sphere._center;
    FLOAT fA0 = D3DXVec3Dot(&kDiff, &kDiff) - sphere._radius * sphere._radius;
    D3DXVECTOR3 direction = L2 - L1;
    D3DXVec3Normalize(&direction, &direction);
    FLOAT fA1 = D3DXVec3Dot(&direction, &kDiff);
    FLOAT fDiscr = fA1 * fA1 - fA0;
    if (fDiscr < 0) {
        return false;
    }

    FLOAT extent = D3DXVec3Length(&(L2 - L1));
    FLOAT fTmp0 = extent * extent + fA0;
    FLOAT fTmp1 = 2 * fA1 * extent;
    FLOAT fQM = fTmp0 - fTmp1;
    FLOAT fQP = fTmp0 + fTmp1;
    if (fQM * fQP <= 0) {
        return true;
    }

    return fQM > 0 && fabs(fA1) < extent;
}

int Toolkit::GetIntersection(float fDst1, float fDst2, D3DXVECTOR3 P1, D3DXVECTOR3 P2, D3DXVECTOR3 &Hit) {
    if ((fDst1 * fDst2) >= 0.0f) return 0;
    if (fDst1 == fDst2) return 0;
    Hit = P1 + (P2-P1) * (-fDst1 / (fDst2-fDst1));
    return 1;
}

void Toolkit::GetVertices(const d3d::BoundingBox* boundingBox, D3DXVECTOR4* vertices) {
    vertices[0] = D3DXVECTOR4(boundingBox->_min.x, boundingBox->_min.y, boundingBox->_min.z, 1.0f);
    vertices[1] = D3DXVECTOR4(boundingBox->_min.x, boundingBox->_max.y, boundingBox->_min.z, 1.0f);
    vertices[2] = D3DXVECTOR4(boundingBox->_max.x, boundingBox->_max.y, boundingBox->_min.z, 1.0f);
    vertices[3] = D3DXVECTOR4(boundingBox->_max.x, boundingBox->_min.y, boundingBox->_min.z, 1.0f);
    vertices[4] = D3DXVECTOR4(boundingBox->_max.x, boundingBox->_max.y, boundingBox->_max.z, 1.0f);
    vertices[5] = D3DXVECTOR4(boundingBox->_min.x, boundingBox->_max.y, boundingBox->_max.z, 1.0f);
    vertices[6] = D3DXVECTOR4(boundingBox->_min.x, boundingBox->_min.y, boundingBox->_max.z, 1.0f);
    vertices[7] = D3DXVECTOR4(boundingBox->_max.x, boundingBox->_min.y, boundingBox->_max.z, 1.0f);
}

int Toolkit::InBox(D3DXVECTOR3 Hit, d3d::BoundingBox box, const int Axis) {
    if (Axis == 1 && Hit.z > box._min.z && Hit.z < box._max.z && Hit.y > box._min.y && Hit.y < box._max.y) return 1;
    if (Axis == 2 && Hit.z > box._min.z && Hit.z < box._max.z && Hit.x > box._min.x && Hit.x < box._max.x) return 1;
    if (Axis == 3 && Hit.x > box._min.x && Hit.x < box._max.x && Hit.y > box._min.y && Hit.y < box._max.y) return 1;
    return 0;
}

double Toolkit::RandomFloat() {
    return rand() / (static_cast<double>(RAND_MAX) + 1.0);
}

double Toolkit::RandomFloat(double min, double max) {
    if (min > max) {
        double temp = min;
        min = max;
        max = temp;
    }

    return (rand() / (static_cast<double>(RAND_MAX) + 1.0)) * (max - min) + min;
}

int Toolkit::RandomInt() {
    return rand();
}

int Toolkit::RandomInt(int min, int max) {
    if (min > max) {
        int temp = min;
        min = max;
        max = temp;
    }

    return rand() % (max - min + 1) + min;
}

}
